From 2a165ac2198a3d92342f69cd59d55eca412e1b53 Mon Sep 17 00:00:00 2001 From: Antoine Musso Date: Wed, 2 Mar 2011 20:40:40 +0000 Subject: [PATCH] Bug 2429 allow selection of associated namespace in recent changes Done by adding yet another checkbox in Special:RecentChanges. The feature also support namespace inversion. For example, if you have selected the TALK namespace with inversion and associated namespace, you will be shown any changes which is not NS_MAIN or NS_TALK. Tests: SpecialRecentchanges tests only this feature. I had to filter out the rc_timestamp condition which might cause trouble if the test suite is run on another day. A better solution remains to be implemented. --- RELEASE-NOTES | 1 + includes/specials/SpecialRecentchanges.php | 28 +++- languages/messages/MessagesEn.php | 1 + maintenance/language/messages.inc | 1 + .../specials/SpecialRecentchanges.php | 134 ++++++++++++++++++ 5 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 tests/phpunit/includes/specials/SpecialRecentchanges.php diff --git a/RELEASE-NOTES b/RELEASE-NOTES index ea75f8dacd..1dcb80cda8 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -81,6 +81,7 @@ it from source control: http://www.mediawiki.org/wiki/Download_from_SVN safely enabled. A ZIP file reader was added which can scan a ZIP file for potentially dangerous Java applets. This allows applets to be blocked specifically, rather than all ZIP files being blocked. +* (bug 2429) Allow selection of associated namespace in recent changes === Bug fixes in 1.18 === * (bug 23119) WikiError class and subclasses are now marked as deprecated diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php index dea902b6bf..3277902442 100644 --- a/includes/specials/SpecialRecentchanges.php +++ b/includes/specials/SpecialRecentchanges.php @@ -55,6 +55,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { $opts->add( 'namespace', '', FormOptions::INTNULL ); $opts->add( 'invert', false ); + $opts->add( 'associated', false ); $opts->add( 'categories', '' ); $opts->add( 'categories_any', false ); @@ -284,13 +285,26 @@ class SpecialRecentChanges extends IncludableSpecialPage { # Namespace filtering if( $opts['namespace'] !== '' ) { - if( !$opts['invert'] ) { - $conds[] = 'rc_namespace = ' . $dbr->addQuotes( $opts['namespace'] ); + $selectedNS = $dbr->addQuotes( $opts['namespace'] ); + $operator = $opts['invert'] ? '!=' : '='; + $boolean = $opts['invert'] ? 'AND' : 'OR'; + + # namespace association (bug 2429) + if( !$opts['associated'] ) { + $condition = "rc_namespace $operator $selectedNS"; } else { - $conds[] = 'rc_namespace != ' . $dbr->addQuotes( $opts['namespace'] ); + # Also add the associated namespace + $associatedNS = $dbr->addQuotes( + MWNamespace::getAssociated( $opts['namespace'] ) + ); + $condition = "(rc_namespace $operator $selectedNS " + . $boolean + . " rc_namespace $operator $associatedNS)"; } - } + $conds[] = $condition; + } +wfVarDump( $conds ); return $conds; } @@ -463,7 +477,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { $defaults = $opts->getAllValues(); $nondefaults = $opts->getChangedValues(); - $opts->consumeValues( array( 'namespace', 'invert', 'tagfilter', + $opts->consumeValues( array( 'namespace', 'invert', 'associated', 'tagfilter', 'categories', 'categories_any' ) ); $panel = array(); @@ -555,6 +569,7 @@ class SpecialRecentChanges extends IncludableSpecialPage { /** * Creates the choose namespace selection * + * @todo Uses radio buttons (HASHAR) * @param $opts FormOptions * @return String */ @@ -562,7 +577,8 @@ class SpecialRecentChanges extends IncludableSpecialPage { $nsSelect = Xml::namespaceSelector( $opts['namespace'], '' ); $nsLabel = Xml::label( wfMsg('namespace'), 'namespace' ); $invert = Xml::checkLabel( wfMsg('invert'), 'invert', 'nsinvert', $opts['invert'] ); - return array( $nsLabel, "$nsSelect $invert" ); + $associated = Xml::checkLabel( wfMsg('namespace_association'), 'associated', 'nsassociated', $opts['associated'] ); + return array( $nsLabel, "$nsSelect $invert $associated" ); } /** diff --git a/languages/messages/MessagesEn.php b/languages/messages/MessagesEn.php index 68650e6317..2465c2164a 100644 --- a/languages/messages/MessagesEn.php +++ b/languages/messages/MessagesEn.php @@ -2964,6 +2964,7 @@ $1', # Namespace form on various pages 'namespace' => 'Namespace:', 'invert' => 'Invert selection', +'namespace_association' => 'Associated namespace', 'blanknamespace' => '(Main)', # Contributions diff --git a/maintenance/language/messages.inc b/maintenance/language/messages.inc index 2bf4ad55bd..6247843e49 100644 --- a/maintenance/language/messages.inc +++ b/maintenance/language/messages.inc @@ -1989,6 +1989,7 @@ $wgMessageStructure = array( 'nsform' => array( 'namespace', 'invert', + 'namespace_association', 'blanknamespace', ), 'contributions' => array( diff --git a/tests/phpunit/includes/specials/SpecialRecentchanges.php b/tests/phpunit/includes/specials/SpecialRecentchanges.php new file mode 100644 index 0000000000..48e31f3abc --- /dev/null +++ b/tests/phpunit/includes/specials/SpecialRecentchanges.php @@ -0,0 +1,134 @@ +rc = new SpecialRecentChanges(); + $formOptions = $this->rc->setup( null ); + + # Filter out rc_timestamp conditions which depends on the test runtime + # This condition is not needed as of march 2, 2011 -- hashar + # FIXME: find a way to generate the correct rc_timestamp + $queryConditions = array_filter( + $this->rc->buildMainQueryConds( $formOptions ), + 'SpecialRecentchangesTest::filterOutRcTimestampCondition' + ); + + $this->assertEquals( + $expected, + $queryConditions, + $message + ); + + $wgRequest = $savedGlobal; + } + + /** return false if condition begin with 'rc_timestamp ' */ + private static function filterOutRcTimestampCondition( $var ) { + return (false === strpos( $var, 'rc_timestamp ' )); + + } + + public function testRcNsFilter() { + $this->assertConditions( + array( # expected + 'rc_bot' => 0, + #0 => "rc_timestamp >= '20110223000000'", + 1 => "rc_namespace = '0'", + ), + array( + 'namespace' => NS_MAIN, + ), + "rc conditions with no options (aka default setting)" + ); + } + + public function testRcNsFilterInversion() { + $this->assertConditions( + array( # expected + #0 => "rc_timestamp >= '20110223000000'", + 'rc_bot' => 0, + 1 => sprintf( "rc_namespace != '%s'", NS_MAIN ), + ), + array( + 'namespace' => NS_MAIN, + 'invert' => 1, + ), + "rc conditions with namespace inverted" + ); + } + + /** + * @bug 2429 + * @dataProvider provideNamespacesAssociations + */ + public function testRcNsFilterAssociation( $ns1, $ns2 ) { + $this->assertConditions( + array( # expected + #0 => "rc_timestamp >= '20110223000000'", + 'rc_bot' => 0, + 1 => sprintf( "(rc_namespace = '%s' OR rc_namespace = '%s')", $ns1, $ns2 ), + ), + array( + 'namespace' => $ns1, + 'associated' => 1, + ), + "rc conditions with namespace inverted" + ); + } + + /** + * @bug 2429 + * @dataProvider provideNamespacesAssociations + */ + public function testRcNsFilterAssociationWithInversion( $ns1, $ns2 ) { + $this->assertConditions( + array( # expected + #0 => "rc_timestamp >= '20110223000000'", + 'rc_bot' => 0, + 1 => sprintf( "(rc_namespace != '%s' AND rc_namespace != '%s')", $ns1, $ns2 ), + ), + array( + 'namespace' => $ns1, + 'associated' => 1, + 'invert' => 1, + ), + "rc conditions with namespace inverted" + ); + } + + /** + * Provides associated namespaces to test recent changes + * namespaces association filtering. + */ + public function provideNamespacesAssociations() { + return array( # (NS => Associated_NS) + array( NS_MAIN, NS_TALK), + array( NS_TALK, NS_MAIN), + ); + } + +} + + -- 2.20.1